#include "texture2d.h"
#include "ext/stb_image.h"

namespace vortex
{
    Texture2D::Texture2D()
    {
        glGenTextures(1, &texture_id);
    }

    Texture2D::~Texture2D()
    {
        glDeleteTextures(1, &texture_id);
    }

    std::shared_ptr<Texture2D> Texture2D::fromImageFile(const std::string& filepath)
    {
        std::shared_ptr<Texture2D> texture = std::make_shared<Texture2D>();
        texture->load_image_file(filepath);
        return texture;
    }

    bool Texture2D::load_image_file(const std::string& filepath)
    {
        int x, y, n;
        int force_channels = 4;
        unsigned char* image_data = stbi_load(filepath.c_str(), &x, &y, &n, force_channels);
        if (!image_data) {
            fprintf(stderr, "ERROR: could not load %s\n", filepath.c_str());
            return false;
        }
        // NPOT check
        if ((x & (x - 1)) != 0 || (y & (y - 1)) != 0) { fprintf(stderr, "WARNING: texture %s is not power-of-2 dimensions\n", filepath.c_str()); }
        int width_in_bytes = x * 4;
        unsigned char* top = NULL;
        unsigned char* bottom = NULL;
        unsigned char temp = 0;
        int half_height = y / 2;

        for (int row = 0; row < half_height; row++) {
            top = image_data + row * width_in_bytes;
            bottom = image_data + (y - row - 1) * width_in_bytes;
            for (int col = 0; col < width_in_bytes; col++) {
                temp = *top;
                *top = *bottom;
                *bottom = temp;
                top++;
                bottom++;
            }
        }
        // glGenTextures(1, texture_id);

        // glActiveTexture(GL_TEXTURE0 + texture_slot);
        glBindTexture(GL_TEXTURE_2D, texture_id);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
        glGenerateMipmap(GL_TEXTURE_2D);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        GLfloat max_aniso = 0.0f;
        glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_aniso);
        // set the maximum!
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso);

        // free image data
        free(image_data);

        return true;
    }

}
